﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

using SlimDX;
using SlimDX.DirectInput;

namespace DemoFramework
{
    public class BasicInput : IDisposable
    {
        #region Attributes
        Device<KeyboardState> _keyboardDevice;
        Device<MouseState> _mouseDevice;

        private KeyboardState _keyboardState;
        private MouseState _mouseState;

        private IEnumerable<BufferedData<KeyboardState>> _keyboardBufferedData;
        private IEnumerable<BufferedData<MouseState>> _mouseBufferedData;

        private bool _keyboardAvailable;
        private bool _mouseAvailable;
        #endregion

        #region Properties
        public KeyboardState KeyboardState
        {
            get { return _keyboardState; }
            private set { _keyboardState = value; }
        }

        public IEnumerable<BufferedData<KeyboardState>> KeyboardBufferedData
        {
            get { return _keyboardBufferedData; }
            private set { _keyboardBufferedData = value; }
        }

        public MouseState MouseState
        {
            get { return _mouseState; }
            private set { _mouseState = value; }
        }

        public IEnumerable<BufferedData<MouseState>> MouseBufferedData
        {
            get { return _mouseBufferedData; }
            private set { _mouseBufferedData = value; }
        }

        public bool KeyboardAvailable
        {
            get { return _keyboardAvailable; }
            private set { _keyboardAvailable = value; }
        }

        public bool MouseAvailable
        {
            get { return _mouseAvailable; }
            private set { _mouseAvailable = value; }
        }
        #endregion

        public BasicInput(IntPtr controlHandle)
        {
            DirectInput directInput = new DirectInput();
            CooperativeLevel cooperativeLevel = CooperativeLevel.Nonexclusive | CooperativeLevel.Foreground | CooperativeLevel.NoWinKey;

            try
            {
                _keyboardDevice = new Device<KeyboardState>(directInput, SystemGuid.Keyboard);
                _keyboardDevice.SetCooperativeLevel(controlHandle, cooperativeLevel);
                _keyboardDevice.Properties.BufferSize = 16;
            }
            catch (DirectInputException e)
            {
                MessageBox.Show(e.Message);
                return;
            }

            try
            {
                _mouseDevice = new Device<MouseState>(directInput, SystemGuid.Mouse);
                _mouseDevice.SetCooperativeLevel(controlHandle, cooperativeLevel);
                _mouseDevice.Properties.BufferSize = 16;
            }
            catch (DirectInputException e)
            {
                MessageBox.Show(e.Message);
                return;
            }
        }

        public void Update()
        {
            UpdateKeyboard();
            UpdateMouse();
        }

        private void UpdateKeyboard()
        {
            if (_keyboardDevice.Acquire().IsFailure)
            {
                //This is normal in CooperativeLevel.Foreground
                //Console.WriteLine("Can't acquire Keybord.");
                return;
            }
            else
            {
                if (_keyboardDevice.Poll().IsFailure)
                {
                    Console.WriteLine("Can't poll Keybord.");
                    _keyboardAvailable = false;
                    return;
                }
                else
                {
                    _keyboardBufferedData = _keyboardDevice.GetBufferedData();
                    _keyboardState = _keyboardDevice.GetCurrentState();

                    _keyboardAvailable = true;
                }
            }
        }

        private void UpdateMouse()
        {
            if (_mouseDevice.Acquire().IsFailure)
            {
                //This is normal in CooperativeLevel.Foreground
                //Console.WriteLine("Can't acquire Mouse.");
                return;
            }
            else
            {
                if (_mouseDevice.Poll().IsFailure)
                {
                    Console.WriteLine("Can't poll Mouse.");
                    _mouseAvailable = false;
                    return;
                }
                else
                {
                    _mouseBufferedData = _mouseDevice.GetBufferedData();
                    _mouseState = _mouseDevice.GetCurrentState();

                    _mouseAvailable = true;
                }
            }
        }

        #region IDisposable Member
        public void Dispose()
        {
            if (_keyboardDevice != null)
            {
                _keyboardDevice.Unacquire();
                _keyboardDevice.Dispose();
                _keyboardDevice = null;
            }

            if (_keyboardState != null)
            {
                _keyboardState = null;
            }

            if (_mouseDevice != null)
            {
                _mouseDevice.Unacquire();
                _mouseDevice.Dispose();
                _mouseDevice = null;
            }

            if (_mouseState != null)
            {
                _mouseState = null;
            }
        }
        #endregion
    }
}
